package se.kth.fericss.quicksort;
import static org.junit.Assert.*;
import java.util.Arrays;
import org.junit.Test;
/**
 * 
 * @author Fredric
 *
 */
public class QuicksorterTest {
	Stopwatch clock = new Stopwatch();
	@Test
	public void testSort() {		
		measure(new QuicksortJava());
		measure(new QuicksortFixedPivot());
		measure(new QuicksortRandomPivot());
		measure(new QuicksortFixedPivotInsertionsort());
		measure(new QuicksortRandomPivotInsertionsort());
		measure(new QuicksortFixedPivotShellsort());
		testK();
	}
	/**
	 * Measures the time to sort the data using the sorter.
	 * Checks that the sorting is accurate.
	 * Prints the results of the measurement to the console.
	 */
	private long measure(Quicksorter sorter) {
		int[] da;
		int[] da2;
		long time=0;
		int k;
		int[] elements = new int[]{1000,10000,100000,1000000};
		System.out.print(""+sorter.getType()+"\nElements:\t1000\t10000\t100000\t1000000");
		Data.Order[] wat = new Data.Order[]{Data.Order.RANDOM, Data.Order.ASCENDING, Data.Order.DESCENDING, Data.Order.SAME_VALUE};
		for(Data.Order enu : wat){
			System.out.print("\n"+enu.toString()+(enu.toString().length()<8?":\t":""));
			for (int i : elements) {
				Data d = new Data(i,i,enu);
				time=0; 
				for(k =0;k<10;k++){
					da = d.get();
					da2= d.get();					
					Arrays.sort(da2);
					clock.reset().start();
					sorter.sort(da,0,da.length-1);
					long temptime = clock.stop().getTime();
					time = k<5? time: (time+ temptime);
					for(int ik = 0;ik <1000;ik++){
						assertTrue(da[ik]==da2[ik]);
					}
				}
				System.out.print("\t"+time/5+" ms");
			}
		}
		System.out.println("");
		return time;
	}
	/**
	 * A method that tests what k value the quicksorter classes should use.
	 */
	private void testK(){
		QuicksortRandomPivotInsertionsort qu = new QuicksortRandomPivotInsertionsort();
		System.out.println(	"Warning, testing what k value the \n" +
							"quicksort method should use for best peformence\n" +
							"This could take about 2-5 minutes!");
		int fastest=qu.k;
		long temptime = 10000000;
		int[] k = new int[]{1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30};
		for(int k2 :k){
			qu.k=k2*2;
			long fas = measureK(qu);
			if(fas<temptime){
				fastest=qu.k;
				temptime=fas;
			}
		}
		System.out.println("The optimal k value for your computer would be: "+fastest);
	}
	/**
	 * Slightly modified version of the measure method.
	 * @param sorter A quicksorter object
	 * @return The time it took for the quicksorter.
	 */
	private long measureK(Quicksorter sorter) {
		int[] da;
		long time=0;
		int k;
		int[] elements = new int[]{1000,10000,100000,1000000};
		Data.Order[] wat = new Data.Order[]{Data.Order.RANDOM};
		for(Data.Order enu : wat){
			for (int i : elements) {
				Data d = new Data(i,i,enu);
				time=0;
				for(k =0;k<15;k++){
					da = d.get();
					clock.reset().start();
					sorter.sort(da,0,da.length-1);
					long temptime = clock.stop().getTime();
					time = k<5? time: (time+temptime);
				}
			}
		}
		return time;
	}
}